// This code is licensed under New BSD Licence. For details see project page at
// http://code.google.com/p/hrissan-cocoa-helpers/source/checkout
#import "SimpleHTTPLoaderChinese.h"
#import <vector>
#import <algorithm>
#import "base64.h"

enum check_state_enum { UNKNOWN, SENDING_DIRECT, DIRECT, SENDING_BOTH, VIA_PROXY };

static check_state_enum proxy_state = UNKNOWN;

static NSString * const dhost = @"hrissansb.appspot.com";
static NSString * const d2host = @"2hrissansb.appspot.com";
static NSString * const phost = @"smartbudgetapp.com/cloud";
static NSString * const p2host = @"2smartbudgetapp.com/cloud";
//static NSPtr<NSMutableDictionary> host_proxies;

@interface GlobalChinese : NSObject<SimpleHTTPLoaderDelegate> {
    std::vector< NSPtr<SimpleHTTPLoaderChinese> > waiting_chinese;
    NSPtr<SimpleHTTPLoader> check_direct;
    NSPtr<SimpleHTTPLoader> check_proxy;
    NSPtr<NSTimer> check_timer;
    NSPtr<NSString> check_string;
}

+(GlobalChinese *)instance;
-(void)addChinese:(SimpleHTTPLoaderChinese *)ch;
-(bool)hasChinese:(SimpleHTTPLoaderChinese *)ch;
-(void)removeChinese:(SimpleHTTPLoaderChinese *)ch;
@end

NSPtr<GlobalChinese> global_chinese;

@implementation GlobalChinese

-(id)init {
    if( (self == [super init]) )
    {
        const int LEN = 9;
        uint8_t bytes[LEN] = {};
        mac_iphone_SecRandomCopyBytes(LEN, bytes);
        check_string = rfc::to_base64([NSData dataWithBytes:bytes length:LEN], rfc::BASE64_TABLE_FILESYSTEM_COMPATIBLE );
    }
    return self;
}

-(NSMutableURLRequest *)get_check_req_proxy:(bool)proxy
{
    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
    
    [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@/check.php?body=%@", proxy ? phost : dhost, check_string.get()]]];
    [request setHTTPMethod:@"GET"];
    [request setValue:@"*/*" forHTTPHeaderField:@"Accept"];
    [request setValue:@"no-cache" forHTTPHeaderField:@"Pragma"];
    return request;
}


+(GlobalChinese *)instance {
    if( !global_chinese.get() )
    {
        global_chinese = [[[GlobalChinese alloc] init] autorelease];
    }
    return global_chinese.get();
}

-(void)addChinese:(SimpleHTTPLoaderChinese *)ch {
    waiting_chinese.push_back(ch);
    if( proxy_state == UNKNOWN )
    {
        NSLog(@"GlobalChinese UNKNOWN -> SENDING_DIRECT");
        proxy_state = SENDING_DIRECT;
        check_direct = [[[SimpleHTTPLoader alloc] initWithDelegate:self] autorelease];
        [check_direct.get() send_request:[self get_check_req_proxy:false]];
		check_timer = [NSTimer scheduledTimerWithTimeInterval:4 target:self selector:@selector(timerClick) userInfo:nil repeats:NO];
    }
}

-(bool)hasChinese:(SimpleHTTPLoaderChinese *)ch {
    int ind = std::find(waiting_chinese.begin(), waiting_chinese.end(), ch) - waiting_chinese.begin();
    return ind != waiting_chinese.size();
}

-(void)removeChinese:(SimpleHTTPLoaderChinese *)ch {
    int ind = std::find(waiting_chinese.begin(), waiting_chinese.end(), ch) - waiting_chinese.begin();
    if( ind != waiting_chinese.size() )
        waiting_chinese.erase(waiting_chinese.begin() + ind);
}

-(void)tellChinese {
    std::vector< NSPtr<SimpleHTTPLoaderChinese> > w2_chinese;
    w2_chinese.swap(waiting_chinese);
    std::for_each(w2_chinese.begin(), w2_chinese.end(), ^(NSPtr<SimpleHTTPLoaderChinese> ch) {
        [ch.get() resend_request];
    });
}

-(void)sendBoth {
    proxy_state = SENDING_BOTH;
    check_direct = [[[SimpleHTTPLoader alloc] initWithDelegate:self] autorelease];
    [check_direct.get() send_request:[self get_check_req_proxy:false]];
    check_proxy = [[[SimpleHTTPLoader alloc] initWithDelegate:self] autorelease];
    [check_proxy.get() send_request:[self get_check_req_proxy:true]];
}

-(void)timerClick {
    NSLog(@"GlobalChinese timerClick");
    // SENDING_DIRECT
    check_timer = 0;
    [check_direct.get() cancel_request];
    check_direct = 0;
    [self sendBoth];
}

-(void)loader:(SimpleHTTPLoader *)loader result:(NSMutableData *)result_data statusCode:(int)statusCode {
	NSString * result_str = [[[NSString alloc] initWithData:result_data encoding:NSUTF8StringEncoding] autorelease];
    bool good_str = result_str && [check_string.get() compare:result_str] == 0;
    if( proxy_state == SENDING_DIRECT )
    {
        check_direct = 0;
        [check_timer.get() invalidate];
        check_timer = 0;
        if( good_str )
        {
            NSLog(@"GlobalChinese SENDING_DIRECT -> DIRECT");
            proxy_state = DIRECT;
            [self tellChinese];
            return;
        }
        NSLog(@"GlobalChinese SENDING_DIRECT -> SENDING_BOTH");
        [self sendBoth];
        return;
    }
    // SENDING_BOTH
    if( loader == check_direct.get() )
    {
        check_direct = 0;
        if( good_str )
        {
            NSLog(@"GlobalChinese SENDING_BOTH -> DIRECT");
            [check_proxy.get() cancel_request];
            check_proxy = 0;
            proxy_state = DIRECT;
            [self tellChinese];
            return;
        }
    }
    if( loader == check_proxy.get() )
    {
        check_proxy = 0;
        if( good_str )
        {
            NSLog(@"GlobalChinese SENDING_BOTH -> VIA_PROXY");
            [check_direct.get() cancel_request];
            check_direct = 0;
            proxy_state = VIA_PROXY;
            [self tellChinese];
            return;
        }
    }
    if( !check_proxy.get() && !check_direct.get() )
    {
        NSLog(@"GlobalChinese SENDING_BOTH -> UNKNOWN");
        proxy_state = UNKNOWN;
        [self tellChinese];
    }
}

@end

@implementation SimpleHTTPLoaderChinese

-(void)dealloc {
    [self cancel_request];
    [super dealloc];
}

+(void)testAgain {
    if( proxy_state == DIRECT || proxy_state == VIA_PROXY )
        proxy_state = UNKNOWN;
}

-(bool)loading {
    if( waiting_request.get() )
        return true;
    return [super loading];
}

- (void)cancel_request
{
    if( waiting_request.get() )
    {
        [[GlobalChinese instance] removeChinese:self];
        waiting_request = 0;
        return;
    }
    [super cancel_request];
}

-(void)resend_request:(NSMutableURLRequest *)request {
    if( proxy_state == UNKNOWN )
    {
        NSLog(@"resend_request: UNKNOWN state");
        if( delegate )
            [delegate loader:self result:0 statusCode:0];
        return;
    }
    NSString * prev_str = [[request URL] absoluteString];
    if( proxy_state == VIA_PROXY )
    {
        NSLog(@"resend_request: {%@}", prev_str);
        prev_str = [prev_str stringByReplacingOccurrencesOfString:dhost withString:phost];
        [request setURL:[[[NSURL alloc] initWithString:prev_str] autorelease]];
    }
    NSLog(@"resend_request: {%@}", prev_str);
    [super send_request:request];
}

-(void)resend_request {
    if( !waiting_request.get() ) // TODO check protection
        return;
    NSMutableURLRequest * req = [[waiting_request.get() retain] autorelease];
    waiting_request = 0;
    [self resend_request:req];
}

-(void)send_request:(NSMutableURLRequest *)request {
    if( proxy_state == DIRECT || proxy_state == VIA_PROXY )
    {
        [self resend_request:request];
        return;
    }
    waiting_request = request;
    [[GlobalChinese instance] addChinese:self];
}

@end
